package jfilters.filters.noise;

/*
    Copyright Janne Liljeblad 2008.

    This file is part of JFilters.

    JFilters is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JFilters is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with JFilters.  If not, see <http://www.gnu.org/licenses/>.
*/

import jfilters.filters.JFilter;
import jfilters.libmath.JFMath;
import jfilters.lib.PixelRow;
import java.util.Random;
import java.awt.image.*;
import java.awt.*;

public class JFRandomize extends JFilter
{
	private static final int RNDM_HURL = 1;
	private static final int RNDM_PICK = 2;
	private static final int RNDM_SLUR = 3;
	
	private static final int SEED_DEFAULT = 10;
	private static final int SEED_USER = 11;
	private static final int SCALE_WIDTH = 100;

	int rndm_type = RNDM_SLUR;/*mode*/
	double  rndm_pct = 50.0;     /* likelihood of randomization (as %age) */
	int  rndm_rcount = 1;  /* repeat count */
	boolean randomize = false;    /* Whether to use a random seed */
	int seed = SEED_DEFAULT;         /* seed value for g_rand_set_seed() function */

	private Random random;

	public JFRandomize(){}

	public BufferedImage filter( BufferedImage sourceImg, BufferedImage destinationImg )
	{
		WritableRaster destination = destinationImg.getRaster();
		WritableRaster source = sourceImg.getRaster();

  		int bytes = source.getNumBands();

		int x1 = 0;
		int y1 = 0;
		int x2 = source.getWidth();
		int y2 = source.getHeight();

		int width  = x2 - x1;
		int height = y2 - y1;

		random = new Random();

		PixelRow pr = prepareRow( source, y1 -1 );
		PixelRow cr = prepareRow( source, y1 );
		PixelRow nr;
		PixelRow dr;
		PixelRow tmp;



		/*
		*  prepare the first row and previous row
		*/
		pr = prepareRow( source, y1 -1 );// wont be claped
		cr = prepareRow( source, y1 );

		int k = 0;
		int i, j = 0;
		/*
		*  loop through the rows, applying the selected convolution
		*/

	
		for (int row = y1; row < y2; row++)
		{
			/*  prepare the next row  */
			nr = prepareRow( source, row + 1 );
			dr = prepareRow( destination, row );

			for (int col = 0; col < (x2 - x1); col++)
			{
				//--- Select pixel for randomization.
				if ( getRandInRange( 0, 100 ) <= rndm_pct )
				{
					switch (rndm_type)
					{
						/*
						*  HURL
						*      Just assign a random value.
						*/
						case RNDM_HURL:
							for ( j = 0; j < bytes; j++)
							{
								i = col * bytes + j;
								dr.setSample( i ,getRandInRange( 0, 256));
							}
							break;
				
						/*
						*  PICK
						*      pick at random from a neighboring pixel.
						*/
						case RNDM_PICK:
							k = getRandInRange( 0, 9);
							for ( j = 0; j < bytes; j++)
							{
								i = col * bytes + j;
					
								switch (k)
								{
									case 0:
									//*d++ = (gint) pr[i - bytes];
									dr.setSample( i , pr.getSample( i - bytes ));
									break;
									case 1:
									dr.setSample( i , pr.getSample( i ));
									break;
									case 2:
									dr.setSample( i , pr.getSample( i + bytes ));
									break;
									case 3:
									dr.setSample( i , cr.getSample( i - bytes ));
									break;
									case 4:
									dr.setSample( i , cr.getSample( i ));
									break;
									case 5:
									dr.setSample( i , cr.getSample( i + bytes ));
									break;
									case 6:
									dr.setSample( i , nr.getSample( i - bytes ));
									break;
									case 7:
									dr.setSample( i , nr.getSample( i ));
									break;
									case 8:
									dr.setSample( i , nr.getSample( i + bytes ));
									break;
								}
							}
							break;
						/*
						*  SLUR
						*      80% chance it's from directly above,
						*      10% from above left,
						*      10% from above right.
						*/
						case RNDM_SLUR:
							k =  getRandInRange( 0, 10 );
							for (j = 0; j < bytes; j++)
							{
								i = col*bytes + j;
								switch (k )
								{
									case 0:
									//*d++ = (gint) pr[i - bytes];
									dr.setSample( i , pr.getSample( i - bytes ));
									break;
									case 9:
									dr.setSample( i , pr.getSample( i + bytes ));
									break;
									default:
									dr.setSample( i , pr.getSample( i ));
									break;
								}
							}
							break;
					}

				}
				/*
				*  Otherwise, this pixel was not selected for randomization,
				*  so use the current value.
				*/
				else
				{
					for (j = 0; j < bytes; j++)
					{
						i = col * bytes + j;
						dr.setSample( i , nr.getSample( i ));
						//*d++ = (gint) cr[col*bytes + j];
					}
				}
			}
			/*
			*  Save the modified row, shuffle the row pointers, and every
			*  so often, update the progress meter.
			*/
			/* Write data into raster */
			dr.commitData();

			tmp = pr;
			pr = cr;
			cr = nr;
			nr = tmp;
		}
		return destinationImg;
	}

	private PixelRow prepareRow( WritableRaster raster, int y )
	{
		y = JFMath.CLAMP( y, 0, raster.getHeight() - 1 );
		return new PixelRow( raster, y, PixelRow.CLAMP_EDGES );
	}

	private int getRandInRange( int low, int high )
	{
		double rand = random.nextDouble();
		int range = high - low;
		double value = range * rand;
		return low + (int) Math.floor( value );
	}

}//end class